﻿package com.atn.edamame 
{
	import flash.text.TextField;
	import flash.utils.*;
	import flash.net.*; 
	import flash.events.*;
    import flash.display.*;
	import mx.containers.HBox;
	import mx.controls.Button;
	import mx.controls.Text;
	import mx.core.UIComponent;
	import mx.controls.TextInput;
	import mx.containers.Canvas;

	import mx.utils.ObjectUtil;
	import org.libspark.asreflect.*;
	
	import com.atn.edamame.*;
	import com.atn.edamame.googlews.*;
	import com.atn.edamame.tools.*;
	
	public class EdamameRunner extends HBox
	{
		public var loading:Sprite;
		[Embed(source = '../../../loading.swf')]
		private var LoadingSWF:Class;
		private var edamameToolFactory:EdamameToolFactory = EdamameToolFactory.getInstance();
		private var stringWidth:int = 150;

		public var edamame:XML; // edamame souce code
		
		private var code:Array; //contains intermediate code for execute
		public var register:Object; //contains runtime data
		
		private var varCount:int = 0; // number of variables which is used for variable naming
		
		public var onRunFinish:Function = function(register:Object):void { };//call back when execution of Edamame is completed
		/**
		 * Handler for Edamame is loadted
		 * @param	results contains edamame code
		 */
		protected function onLoadComplete(results:Object) :void {
			//TODO error handle for invalid Edamame code	
			setEdamame(new XML(results));
		}
		/**
		 * setter for Edamame
		 * This function also generates Edamme intermediate code
		 * @param	edamame Edamame code
		 */
		public function setEdamame(edamame:XML):void
		{
			this.edamame = edamame;
			//init 
			initEdamame();
			//select input node
			var inputList:XMLList = edamame.EdamameControl.(className == "com.atn.edamame.tools::InputRepeat");
			for (var i:Object in inputList)
			{	
				//TODO define op class
				var op :Object= { type:"var", name:"input" + i };
				code.push(op);
				
				traceInputData(inputList[i], "input" + i);
				
				//create input user interface
				var valueInput:TextInput = new TextInput();
				valueInput.text = "baseball";
				//valueInput.width = 200;
				valueInput.height = 20;
				valueInput.addEventListener(Event.CHANGE, function ():void {
					op.value = valueInput.text;
				} );
				addChild(valueInput);
			}
			//create button for execution
			var runButton:Button = new Button();
			runButton.label = "run";
			//runButton.width = 200;
			runButton.addEventListener(MouseEvent.CLICK, function():void {
				// run Edamame
				runEdamame(0);
			});
			addChild(runButton);
		}
		/**
		 * initialize Edamame running environment
		 */
		private function initEdamame():void
		{
			code = new Array();
			varCount = 0;	
			register = new Object();
		}
		/**
		 * execute Edamame intermetiate code
		 * @param	offset offset of intermediate code 
		 */
		public function runEdamame(offset:int):void
		{
			/*
			 * if there are no more intermediate code 
			 * finish execution
			 */ 
			if (code.length - 1 < offset)
			{
				//call back
				onRunFinish(register);
				return ;
			}
			var op:Object = code[offset];
			//trace(op.type);
			if ( op.type == "var" )
			{
				//TODO: create copy code
				//trace("var " + op.name);
				if(op.copyfrom){
					register[op.name] = ObjectUtil.copy(register[op.copyfrom]);
				}else {
					register[op.name] = new Object();
					register[op.name].value = op.value ? [op.value] : ["baseball"];
				}
				runEdamame(offset + 1);
			}else
			{
				//trace("func " + op.name + " " + op.arg);
				// execute code
				op.obj.exec(register[op.arg],
					function(result:Object):void
					{
						runEdamame(offset + 1);
					}
				);
			}
		}
		/**
		 * Generates intermediate code which is related on a input filed
		 * @param	input definition of input control
		 * @param	varname name of variable
		 */
		private function traceInputData(input:XML,varname:String):void
		{
			var startX:int = int(input.x); //left side position of this control
			var endX:int = startX + int(stringWidth); //right side position of this control
			var controls:XMLList = edamame.EdamameControl.((className != "com.atn.Edamame.tools::InputRepeat"));//list of controls
			var controlArray:Array = new Array();// list of controls which is relivant for the input control
			var control:XML;// a contorol

			for each(control in controls)
			{
				var cWidth:int = int(control.width);
				// is this contorl hits the input ?
				if( ((   int(control.x) <= startX && startX <= int(control.x) + cWidth ) || (int(control.x) <= endX && endX <= int(control.x) + cWidth) ) && int(control.y) > int(input.y) ){
					controlArray.push(control);
				}
			}
			
			// sort by y potision
			controlArray.sort(function (a:XML,b:XML):Number
			{
				if (a.y > b.y)
				{
					return 1;
				}else if (a.y == b.y)
				{
					return 0;
				}else
				{
					return -1;
				}
			});
			
			for each(control in controlArray)
			{
				// if the control is Copy control
				// this code should be written in Copy Class
				if( control.className == "com.atn.edamame.tools::Copy" ){
					
					var inputLeft:XML = <EdamameControl></EdamameControl>;
					inputLeft.x = int(control.x);
					inputLeft.y = int(control.y) + 10;
					
					var inputRight:XML = <EdamameControl></EdamameControl>;
					inputRight.x = int(control.x) + control.width;
					inputRight.y = int(control.y) + 10;
					//adding intermediate code
					code.push({type:"var",name:varname + "Left",copyfrom:varname});
					code.push({type:"var",name:varname + "Right",copyfrom:varname});
					//start generating 
					traceInputData(inputLeft, varname + "Left");
					traceInputData(inputRight,varname + "Right");
					break;
				}else
				{
					//another control
					//createing Object
					var clazz:Class = flash.utils.getDefinitionByName(control.className) as Class;
					var gcon:* = new clazz();
					gcon.x = control.x;
					gcon.y = control.y;
					gcon.description = control.description;
					for (var j:Object in control.properties.property)
					{
						gcon[control.properties.property[j].name] = control.properties.property[j].value;
					}
					code.push({type:"function",name:control.className,arg:varname,obj:gcon});
				}
			}
			
		}
		// event handler when loding the Edamame souce code is failed 
		protected function onFail(results:Object) :void
		{
			trace("ng" + (results as String));
		}
		/**
		 * loading Edamame souce code
		 * @param	edamameID
		 */
		public function load(edamameID:int):void {
			var responder:Responder = new Responder(onLoadComplete, onFail);
			GConnection.getInstance().getConnection().call("loadEdamame", responder, edamameID);
		}
			
		public function EdamameRunner() 
		{
			
		}
		
	}
	
}